package com.zelin.seckill.service.task;

import com.alibaba.fastjson.JSON;
import com.zelin.dao.SeckillGoodsDao;
import com.zelin.entity.SeckillGoodsEntity;
import com.zelin.entity.SeckillOrderEntity;
import com.zelin.entity.SeckillStatus;
import com.zelin.utils.IdWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * ------------------------------
 * 功能：多线程下单
 * 作者：WF
 * 微信：hbxfwf13590332912
 * 创建时间：2021/8/19-16:28
 * ------------------------------
 */
@Component
public class MultiThreadingCreateOrder {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SeckillGoodsDao goodsDao;
    @Autowired
    private IdWorker idWorker;
    @Async
    public void createOrder()  {
        try {
            // String time = "2021081916";
            // String username = "test";
            // String secKillId = "1";
            //从redis中得到SeckillOrderQueue这个队列的值
            Thread.sleep(20000);

            String orderQueue = redisTemplate.boundListOps("SeckillOrderQueue").rightPop();

            //转换为 SeckillStatus类型
            SeckillStatus seckillStatus = JSON.parseObject(orderQueue, SeckillStatus.class);

            //从SeckillGoodsCountList_商品id的redis队列中取出队列，看是否有内容，如果有证明此商品还没有卖完
            String rightPop = redisTemplate.boundListOps("SeckillGoodsCountList_" + seckillStatus.getSecKillId()).rightPop();
            if(rightPop == null){       //如果为null就证明没有商品了，清除排队数据
                clearQueue(seckillStatus.getUsername());
                return;
            }

            String time = seckillStatus.getTime();
            String secKillId = seckillStatus.getSecKillId()+"";
            String username = seckillStatus.getUsername();

            //第一部分：保存秒杀订单
            //1. 根据秒杀商品号查询秒杀商品
            BoundHashOperations<String, String, String> hashOperations =
                    redisTemplate.boundHashOps("SeckillGoods_" + time);

            String s = hashOperations.get(secKillId + "");
            SeckillGoodsEntity seckillGoodsEntity = JSON.parseObject(s, SeckillGoodsEntity.class);
            //2. 商品是否存在，并且是否有库存
            if(seckillGoodsEntity == null || seckillGoodsEntity.getStockCount() <= 0){
                throw new RuntimeException("商品己售罄");
            }
            //3. 将秒杀的订单存到redis中
            SeckillOrderEntity seckillOrderEntity = new SeckillOrderEntity();
            seckillOrderEntity.setId(idWorker.nextId());
            seckillOrderEntity.setCreateTime(new Date());
            seckillOrderEntity.setMoney(seckillGoodsEntity.getCostPrice());
            seckillOrderEntity.setSeckillId(new Long(secKillId));
            seckillOrderEntity.setStatus("0");      //代表未支付
            seckillOrderEntity.setUserId(username); //登录用户
            //4. 将秒杀订单保存到redis中
            redisTemplate.boundHashOps("SeckillOrder").put(username, JSON.toJSONString(seckillOrderEntity));

            //第二部分：扣减库存，处理秒杀商品
            //2.1 扣减一个商品数量
            //seckillGoodsEntity.setStockCount(seckillGoodsEntity.getStockCount() - 1);

            //2.2 通过自增键得到商品的真实库存量，因为高并发场景，可能存在着数据的错乱(得到精准的库存量)
            Long goodsCount = redisTemplate.boundHashOps("SeckillGoodsCount").increment(seckillGoodsEntity.getId() + "", -1);
            seckillGoodsEntity.setStockCount(new Integer(goodsCount + ""));


            //2.3 重新判断是否库存为0
            if(seckillGoodsEntity.getStockCount() <= 0){
                //2.3.1 将此商品重新设置回数据库中
                goodsDao.updateById(seckillGoodsEntity);
                //2.3.2 将此商品从redis中删除
                redisTemplate.boundHashOps("SeckillGoods_" + time).delete(secKillId+"");
            }else{  //如果此商品的库存还有，就重新设置回redis
                redisTemplate.boundHashOps("SeckillGoods_" + time).put(secKillId+"",JSON.toJSONString(seckillGoodsEntity));
            }
            //重新改回状态值
            seckillStatus.setStatus(2);   //下单后，等待支付
            seckillStatus.setOrderId(seckillOrderEntity.getId());
            seckillStatus.setMoney(seckillOrderEntity.getMoney().floatValue());
            redisTemplate.boundHashOps("UserQueueStatus").put(username,JSON.toJSONString(seckillStatus));

            //放一个登录名到redis中，为后面支付宝异步回调做准备
            redisTemplate.opsForValue().set(seckillOrderEntity.getId()+"",username);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("结束下单...");
    }

    /**
     * 功能: 清除排队相关的数据
     * 参数:
     * 返回值: void
     * 时间: 2021/8/20 15:43
     */
    private void clearQueue(String username) {
        //1. 清除是否重复排队标识
        redisTemplate.boundHashOps("UserQueueCount").delete(username);
        //2. 清除排队的标识信息
        redisTemplate.boundHashOps("UserQueueStatus").delete(username);
    }
}
